import { Injectable, Req, Inject } from '@nestjs/common';
import { LoginDto } from './dto/create-login.dto';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../user/entities/user.entity';
import { BusinessException } from '../../common/exceptions/business.exception';
import { UpdateLoginDto } from './dto/update-login.dto';
import { ErrorCode } from '../../common/errorcode';
import Redis from 'ioredis';
import { REDIS_KEYS, REDIS_EXPIRE } from '../../common/redis.config';
import { v4 as uuidv4 } from 'uuid';


@Injectable()
export class LoginService {
  constructor(
    @InjectRepository(User) private readonly user: Repository<User>,
    @Inject('REDIS_CLIENT') private readonly redis: Redis,
  ) { }

  async register(loginDto: LoginDto) {
    const user = await this.user.findOne({
      where: {
        username: loginDto.username,
      },
    });
    if (user) {
      // 抛出业务异常，错误码 1001，HTTP 状态码 409
      throw new BusinessException('此用户名已被占用', ErrorCode.FORBIDDEN);
    }
    const data = new User();
    console.log('data', data);

    data.username = loginDto.username;
    data.password = loginDto.password;
    return this.user.save(data);
  }

  findAll() {
    return `This action returns all login`;
  }

  // 生成验证码并存储到 Redis
  async generateCaptcha(sessionId: string) {
    const captcha = require('svg-captcha').create({
      size: 4,
      fontSize: 50,
      width: 100,
      height: 34,
      background: '#cc9966',
    });
    
    // 存储验证码到 Redis，5分钟过期
    const captchaKey = `${REDIS_KEYS.CAPTCHA}${sessionId}`;
    await this.redis.setex(captchaKey, REDIS_EXPIRE.CAPTCHA, captcha.text);
    return {
      data: captcha.data,
      text: captcha.text, // 开发环境可以返回，生产环境应该移除
    };
  }

  // 验证验证码
  async verifyCaptcha(sessionId: string, code: string): Promise<boolean> {
    const captchaKey = `${REDIS_KEYS.CAPTCHA}${sessionId}`;
    const storedCode = await this.redis.get(captchaKey);

    if (!storedCode) {
      return false;
    }
    
    const isValid = storedCode.toLowerCase() === code.toLowerCase();
    
    // 验证后删除验证码，防止重复使用
    if (isValid) {
      await this.redis.del(captchaKey);
    }
    
    return isValid;
  }

  // 登录限流检查
  async checkLoginRateLimit(username: string): Promise<{ canLogin: boolean; message?: string; secondsLeft?: number }> {
    const attemptsKey = `${REDIS_KEYS.LOGIN_ATTEMPTS}${username}`;
    const attempts = await this.redis.get(attemptsKey);
    const maxAttempts = 5; // 最大尝试次数
    
    if (attempts && parseInt(attempts) >= maxAttempts) {
      const ttl = await this.redis.ttl(attemptsKey);
      return { 
        canLogin: false, 
        message: `登录尝试次数过多，请${Math.ceil(ttl)}秒后再试`,
        secondsLeft: ttl
      };
    }
    return { canLogin: true };
  }

  // 记录登录失败
  async recordLoginFailure(username: string) {
    console.log('这个人登录失败了', username);
    
    const attemptsKey = `${REDIS_KEYS.LOGIN_ATTEMPTS}${username}`;
    await this.redis.incr(attemptsKey);
    //记录失败时间
    await this.redis.expire(attemptsKey, REDIS_EXPIRE.LOGIN_ATTEMPTS);
  }

  // 清除登录失败记录
  async clearLoginFailures(username: string) {
    const attemptsKey = `${REDIS_KEYS.LOGIN_ATTEMPTS}${username}`;
    await this.redis.del(attemptsKey);
  }

  async login(request, LoginDto: LoginDto) {
    // 1. 检查登录限流
    const canLogin = await this.checkLoginRateLimit(LoginDto.username);
    if (!canLogin.canLogin) {
      throw new BusinessException(canLogin.message || '登录尝试次数过多，请30分钟后再试', ErrorCode.FORBIDDEN);
    }
    console.log('canLogin', request.sessionID);
    
    // 2. 验证验证码
    const sessionId = request.sessionID || 'default';
    const isCaptchaValid = await this.verifyCaptcha(sessionId, LoginDto.code);
    if (!isCaptchaValid) {
      await this.recordLoginFailure(LoginDto.username);
      throw new BusinessException('验证码错误', ErrorCode.PARAMS_ERROR);
    }

    // 3. 验证用户名密码
    const user = await this.user.findOne({
      where: {
        username: LoginDto.username,
        password: LoginDto.password,
      },
    });
    
    if (!user) {
      await this.recordLoginFailure(LoginDto.username);
      throw new BusinessException('用户名或密码错误', ErrorCode.PARAMS_ERROR);
    }

    // 4. 登录成功，清除失败记录
    await this.clearLoginFailures(LoginDto.username);

    // 5. 生成 token 并存储到 Redis
    const token = uuidv4();
    const safetyUser = this.getSafetyUser(user);
    const userSessionKey = `${REDIS_KEYS.USER_SESSION}${token}`;
    const userTokenKey = `${REDIS_KEYS.USER_TOKEN}${user.userid}`;
    
    // 存储用户会话到 Redis
    await this.redis.setex(userSessionKey, REDIS_EXPIRE.USER_SESSION, JSON.stringify(safetyUser));
    // 存储用户 token 映射
    await this.redis.setex(userTokenKey, REDIS_EXPIRE.USER_TOKEN, token);
    
    // 6. 同时保持 session 兼容性
    request.session.USER_LOGIN_STATE = safetyUser;
    request.session.USER_TOKEN = token;
    
    return {
      ...safetyUser,
      token,
    };
  }

  update(request, updateLoginDto: UpdateLoginDto) {
    const user = this.getLoginUser(request);
    return user;
  }

  //删除用户
  async remove(request,userid: string) {
    const userLoginState = this.getLoginUser(request);
    if (userLoginState.roles!=2) {
      throw new BusinessException('权限不足', ErrorCode.NOT_LOGIN);
    }
    const user = await this.user.findOne({
      where: {
        userid,
      },
    })
    if (!user) {
      throw new BusinessException('用户不存在', ErrorCode.PARAMS_ERROR);
    }
    this.user.update(user, {
      isActive: false
    })
    return `删除成功`;
  }

  //注销
  async userLogout(request,userid: string) {
    // 清除 Redis 中的用户会话
    const token = request.session?.USER_TOKEN;
    if (token) {
      const userSessionKey = `${REDIS_KEYS.USER_SESSION}${token}`;
      const userTokenKey = `${REDIS_KEYS.USER_TOKEN}${userid}`;
      await this.redis.del(userSessionKey);
      await this.redis.del(userTokenKey);
    }
    
    // 清除 session
    request.session.USER_LOGIN_STATE = '';
    request.session.USER_TOKEN = '';
    
    return '注销成功';
  }

  // 从 Redis 获取用户信息
  async getUserFromRedis(token: string) {
    const userSessionKey = `${REDIS_KEYS.USER_SESSION}${token}`;
    const userData = await this.redis.get(userSessionKey);
    return userData ? JSON.parse(userData) : null;
  }

  getLoginUser(request) {
    if (request == null) {
      return null;
    }
    
    // 优先从 Redis 获取
    // const token = request.session?.USER_TOKEN;
    // if (token) {
    //   return this.getUserFromRedis(token);
    // }
    
    // 兼容原有的 session 方式
    const userObj = request.session.USER_LOGIN_STATE;
    if (userObj == null) {
      throw new BusinessException('未登录', ErrorCode.NOT_LOGIN);
    }
    return userObj;
  }

  getSafetyUser(originUser: User) {
    if (originUser == null) {
      return null;
    }
    const safetyUser = new User();
    safetyUser.userid = originUser.userid;
    safetyUser.username = originUser.username;
    safetyUser.password = originUser.password;
    safetyUser.avatarUrl = originUser.avatarUrl;
    safetyUser.roles = originUser.roles;
    safetyUser.isActive = originUser.isActive;
    safetyUser.articles = originUser.articles;
    return safetyUser;
  }
}
